package com.lightjet.macross.base.awf.config;

import com.lightjet.macross.base.awf.domain.BizAgent;
import com.lightjet.macross.base.awf.domain.BizProcessConfig;
import com.lightjet.macross.base.awf.service.BizAgentService;
import com.lightjet.macross.base.awf.service.BizProcessConfigService;
import com.lightjet.macross.base.awf.service.IAssigneeService;
import com.lightjet.macross.base.awf.service.ProcessService;
import com.lightjet.macross.common.util.JwtUtil;
import com.lightjet.macross.common.util.SpringUtil;

import io.netty.util.internal.StringUtil;
import lombok.extern.java.Log;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.ExecutionListener;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.MessageFormat;
import java.util.*;

import static com.lightjet.macross.base.awf.config.AWFConstants.*;
import static com.lightjet.macross.base.awf.enums.AWFInfoEnum.*;

/**
 * @author : lijia
 * @version : 1.0 2019-02-19 17:55
 * description :
 */
@Log
@Component("nodeInitExecutionListener")
public class NodeInitExecutionListener implements ExecutionListener{

    @Resource
    private RepositoryService repositoryService;

    @Resource
    private ProcessService processService;

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private BizAgentService bizAgentService;

    @Resource
    private BizProcessConfigService bizProcessConfigService;

    @Override
    public void notify(DelegateExecution delegateExecution) {
        log.info("触发【"+delegateExecution.getCurrentFlowElement().getName()+"】nodeInitExecutionListener"+delegateExecution.getId()+":"+delegateExecution.getProcessInstanceId());
        if(delegateExecution.getParent()!=null && delegateExecution.getParent().isMultiInstanceRoot())
        {
            log.info("当前节点【"+delegateExecution.getCurrentFlowElement().getName()+"】为会签节点多实例生成的子节点,跳过处理");
            return;//当前节点为会签节点多实例生成的子节点 跳过
        }

        //region Description
        /*
        if(delegateExecution.getVariable("_isjump")!=null && delegateExecution.getVariable("_isjump").equals("t"))
        {
            formlist = processService.GetLastForms(delegateExecution.getProcessInstanceId());
            delegateExecution.setVariable("_isjump",null);
        }
        else {
            processService.ProcessNodeForm(delegateExecution.getProcessInstanceId(), delegateExecution.getCurrentActivityId());
            formlist = processService.GetPreviousForms(delegateExecution.getProcessInstanceId(), delegateExecution.getCurrentActivityId());
        }
        */
        //endregion
        String assigneeFlag = ((UserTask) delegateExecution.getCurrentFlowElement()).getAssignee();
        processService.ProcessNodeForm(delegateExecution.getProcessInstanceId(), delegateExecution.getCurrentActivityId());
        List<HashMap> formlist;
        if(assigneeFlag.equals("${signer}"))
        {
            formlist= processService.GetPreviousForms(delegateExecution.getProcessInstanceId(), delegateExecution.getCurrentActivityId());
        }
        else
        {
            formlist = processService.GetPreviousUnExpiredForms(delegateExecution.getProcessInstanceId(), delegateExecution.getCurrentActivityId());
        }
        if(formlist.size()>0) //取上一节点的表单 nextexcutro 值 分配人员
        {
            Set<String> candidators = new HashSet<>();
            delegateExecution.setVariable(FORMID_INNER_VARIABLE,formlist.get(0).get("_id").toString());//记录下当前最新表单存放的mongodDB id
            //首先尝试从表单 nextexecutor 中获取下一步人员
            if(formlist.get(0).get("nextexecutor")!= null && !StringUtil.isNullOrEmpty(formlist.get(0).get("nextexecutor").toString()))
            {
                String next = formlist.get(0).get("nextexecutor").toString();
                candidators = new HashSet<>(Arrays.asList(next.split(",")));
            }
            else
            {
                //然后尝试从数据库获取配置
                BizProcessConfig config = bizProcessConfigService.GetConfigValue(delegateExecution.getProcessDefinitionId(),delegateExecution.getCurrentFlowElement().getId(), BizProcessConfig.ConfigTypes.ASSIGNEEAPI);
                String expression = config==null? (StringUtil.isNullOrEmpty(delegateExecution.getCurrentFlowElement().getDocumentation())?"":delegateExecution.getCurrentFlowElement().getDocumentation())  : config.getConfigvalue();

                //如果节点定义了Documentation 则按Documentation的规则获取相应的处理人
                if(!StringUtil.isNullOrEmpty(expression))
                {
                    //从流程变量获取发起人ID
                    String _originator = delegateExecution.getVariable(ORIGINATOR_INNER_VARIABLE)==null?"":delegateExecution.getVariable(ORIGINATOR_INNER_VARIABLE).toString();

                    log.info("获取流程人员处理表达式："+expression);
                    //获取表达式
                    //如果表达式包含@
                    if(expression.contains("@"))
                    {

                        String[] expressions = expression.split("@");
                        String handler = expressions[1];

                        if(!StringUtil.isNullOrEmpty(handler)) {
                            String[] handlerexp = handler.split("#");
                            handler = handlerexp[0];
                            String args = handlerexp.length>1?handlerexp[1]:"";
                            switch (expressions[0].toLowerCase()) {
                                case "webapi":
                                    //delegateExecution.getCurrentFlowElement().getDocumentation();
                                    handler = handler + (handler.contains("?") ? "&" : "?") + ("originator=" + _originator)+"&nodename="+ delegateExecution.getCurrentFlowElement().getName() +"&args="+ args;
                                    HttpHeaders headers = new HttpHeaders();
                                    headers.add("exchange-token",JwtUtil.signWithClaims(10,"802sastcasc!",AUTH_CLIENT_TOKEN));
                                    HttpEntity<List<HashMap>> httpEntity = new HttpEntity<List<HashMap>>(formlist,headers);
                                    try {
                                        candidators = new RestTemplate().postForObject(handler, httpEntity, Set.class);
                                    }
                                    catch (Exception e)
                                    {
                                        log.info(MessageFormat.format(GETTASKASSINEE_HANDLERPARSE_ERROR.toString(),delegateExecution.getProcessInstanceId(),delegateExecution.getCurrentFlowElement().getName(),handler,e.getMessage()));
                                        throw new RuntimeException(MessageFormat.format(GETTASKASSINEE_HANDLERPARSE_ERROR.toString(),delegateExecution.getProcessInstanceId(),delegateExecution.getCurrentFlowElement().getName(),handler,e.getMessage()));
                                    }
                                    break;
                                case "bean":
                                    IAssigneeService h = SpringUtil.getBean(handler, IAssigneeService.class);
                                    candidators = h.GetCandidators(formlist,_originator,delegateExecution.getCurrentFlowElement().getName(),args);
                                    break;
                                case "class":
                                    try {
                                        Class assigneeClass = Class.forName(handler);
                                        Object obj = assigneeClass.newInstance();
                                        if (obj instanceof IAssigneeService)
                                        {
                                            candidators =((IAssigneeService) obj).GetCandidators(formlist,_originator,delegateExecution.getCurrentFlowElement().getName(),args);
                                        }
                                        else
                                        {
                                            throw new RuntimeException(MessageFormat.format(GETTASKASSINEE_HANDLEUNIMPLEMENTED_ERROR.toString(),delegateExecution.getProcessInstanceId(),delegateExecution.getCurrentFlowElement().getName(),handler));
                                        }

                                    }
                                    catch(Exception e)
                                    {
                                        log.info(MessageFormat.format(GETTASKASSINEE_HANDLERPARSE_ERROR.toString(),delegateExecution.getProcessInstanceId(),delegateExecution.getCurrentFlowElement().getName(),handler,e.getMessage()));
                                        throw new RuntimeException(MessageFormat.format(GETTASKASSINEE_HANDLERPARSE_ERROR.toString(),delegateExecution.getProcessInstanceId(),delegateExecution.getCurrentFlowElement().getName(),handler,e.getMessage()));
                                    }
                                    break;
                                case "value":
                                    candidators = new HashSet<>(Arrays.asList(handler.split(",")));
                                    break;
                                default:
                                    log.info(MessageFormat.format(GETTASKASSINEE_HANDLEUNKOWN_ERROR.toString(),delegateExecution.getProcessInstanceId(),delegateExecution.getCurrentFlowElement().getName(),handler));
                                    throw new RuntimeException(MessageFormat.format(GETTASKASSINEE_HANDLEUNKOWN_ERROR.toString(),delegateExecution.getProcessInstanceId(),delegateExecution.getCurrentFlowElement().getName(),handler));

                            }
                        }
                        else
                        {
                            log.info(MessageFormat.format(GETTASKASSINEE_HANDLEREMPTY_ERROR.toString(),delegateExecution.getProcessInstanceId(),delegateExecution.getCurrentFlowElement().getName(),expression));
                            throw new RuntimeException(MessageFormat.format(GETTASKASSINEE_HANDLEREMPTY_ERROR.toString(),delegateExecution.getProcessInstanceId(),delegateExecution.getCurrentFlowElement().getName(),expression));
                        }
                    }
                    //否则抛错
                    else
                    {
                        log.info(MessageFormat.format(GETTASKASSINEE_EXPRESSION_ERROR.toString(),delegateExecution.getProcessInstanceId(),delegateExecution.getCurrentFlowElement().getName(),expression));
                        throw new RuntimeException(MessageFormat.format(GETTASKASSINEE_EXPRESSION_ERROR.toString(),delegateExecution.getProcessInstanceId(),delegateExecution.getCurrentFlowElement().getName(),expression));

                    }
                }
            }
//            else
//            {
//                String next = formlist.get(0).get("nextexecutor").toString();
//                candidators = new HashSet<>(Arrays.asList(next.split(",")));
//            }
            if(candidators.size()==0)
            {
                throw new RuntimeException(MessageFormat.format(GETTASKASSINEE_ASSINEEEMPTY_ERROR.toString(),delegateExecution.getProcessInstanceId(),delegateExecution.getCurrentFlowElement().getName()));
            }
            //处理候选人代理设置--------------------------------------------------------------！！
            bizAgentService.RefreshExpired(); //刷新过期授权
            Set<String> agents = new HashSet<>();

            for(String candidate : candidators)
            {
                List<BizAgent> agentList = bizAgentService.GetAgentsByPrincipalId(candidate,(byte) 1);
                BizAgent t = agentList.stream().filter(e->e.getGrantedprockey().equals("*") || e.getGrantedprockey().equals(delegateExecution.getProcessDefinitionId().split(":")[0])).findFirst().orElse(null);
                if(t!=null)
                {
                    agents.add(t.getAgentId());
                }
                else
                {
                    agents.add(candidate);
                }
                //bizAgentService.
            }


            //List<String> realCandidators = new ArrayList<>(candidators);
            List<String> realCandidators = new ArrayList<>(agents);

            if(!assigneeFlag.equals("${signer}")) {//非会签节点 根据候选人个数判断 直接指定 还是以候选人方式
                if(candidators.size()>1)
                {
                    delegateExecution.setVariable("assigneeList", realCandidators);
                    delegateExecution.setVariable("assignee", null);
                }
                else
                {
                    delegateExecution.setVariable("assignee", realCandidators.get(0));
                    delegateExecution.setVariable("assigneeList", new ArrayList<String>());
                }
/*                if (next.contains(",")) {
                    String[] nexts = next.split(",");
                    delegateExecution.setVariable("assigneeList", Arrays.asList(nexts));
                    delegateExecution.setVariable("assignee", null);
                } else {
                    delegateExecution.setVariable("assignee", next);
                    delegateExecution.setVariable("assigneeList", new ArrayList<String>());
                }*/
            }
            else //会签节点
            {
                delegateExecution.setVariable("signerList", realCandidators);
                delegateExecution.setVariable("deny", 0);//设置默认否决项为0 当多人会签*/
                /*String[] nexts = {next};
                if (next.contains(",")) {
                    nexts = next.split(",");
                }
                delegateExecution.setVariable("signerList", Arrays.asList(nexts));
                delegateExecution.setVariable("deny", 0);//设置默认否决项为0 当多人会签*/
            }
        }
        else
        {
            throw new RuntimeException(MessageFormat.format(GETFORM_PREVIOUS_ERROR.toString(),delegateExecution.getProcessInstanceId(),"-"));
        }
        //region 参考代码
            /*
            ProcessDefinition processDefinition=repositoryService.createProcessDefinitionQuery() // 创建流程定义查询
                    .processDefinitionId(delegateExecution.getProcessDefinitionId()) // 根据流程定义id查询
                    .singleResult();
            */
        //endregion
    }
}
